/*
 * @(#) java2d.demos.Arcs_Curves.BezierAnim.java	1.25 06/08/29
 * 
 * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduce the above copyright notice, 
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may 
 * be used to endorse or promote products derived from this software without 
 * specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL 
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */

/*
 * CurvedShape
 * 
 * Author: August Lammersdorf, www.InteractiveMesh.com/org
 * Version: 1.0
 * Date: 2008/05/25 
 * 
 * Please create your own implementation.
 * You are allowed to copy all lines you like of this source code 
 * under consideration of the copyrigth notice above (BezierAnim), 
 * but you may not modify, compile, or distribute this 'CurvedShape'. 
 *
*/

package kekeke;

import com.interactivemesh.j3d.community.utils.geometry.AWTShapeExtruder;
import com.interactivemesh.j3d.community.utils.geometry.AWTShapeExtrusion;
import com.interactivemesh.j3d.community.utils.navigation.orbit.OrbitBehaviorInterim;
import com.sun.j3d.utils.pickfast.PickCanvas;

import javax.media.j3d.*;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.util.Enumeration;

final class CurvedShape {

    /* static {
  System.out.println("Extrude !!!");
}      */
    private BoundingSphere globalBounds = null;
    private Canvas3D canvas3D = null;
    private Locale locale = null;
    public BranchGroup sceneBranch = null;
    private BranchGroup viewBranch = null;
    private BranchGroup environmentBranch = null;
    private OrbitBehaviorInterim orbitBehInterim = null;
    private GeneralPath generalPath = null;

    public PickCanvas pickCanvas = null;

    CurvedShape(GeneralPath gp) {
        this.generalPath = gp;
        createUniverse();
        createScene();
        setLive();
        pickCanvas = new PickCanvas(canvas3D, locale);
        pickCanvas.setMode(PickCanvas.TYPE_SHAPE3D);
        float sceneRadius = 1.0f;
        Bounds bounds = sceneBranch.getBounds();
        BoundingSphere sphereBounds = null;
        if (bounds.isEmpty()) {
            sphereBounds = new BoundingSphere();
        } else {
            if (sphereBounds instanceof BoundingSphere)
                sphereBounds = (BoundingSphere) sceneBranch.getBounds();
            else
                sphereBounds = new BoundingSphere(sceneBranch.getBounds());
            sceneRadius = (float) sphereBounds.getRadius();
        }

        orbitBehInterim.setTransFactors(sceneRadius / 2.0f, sceneRadius / 2.0f);
        orbitBehInterim.setZoomFactor(sceneRadius / 2.0f);
        orbitBehInterim.setRotFactors(0.75f, 0.75f);
        orbitBehInterim.setClippingBounds(sphereBounds);
        orbitBehInterim.goHome(true);
    }

    Canvas3D getCanvas3D() {
        return canvas3D;
    }

    private void createScene() {
        Appearance appear = new Appearance();
        Material mat = new Material();
        mat.setDiffuseColor(0.7f, 0.0f, 0.0f);
        mat.setEmissiveColor(0.3f, 0.0f, 0.0f);
        mat.setSpecularColor(0.0f, 0.7f, 0.04f);
        mat.setShininess(8.0f);
        appear.setMaterial(mat);
        PolygonAttributes polyAttr = new PolygonAttributes();
        polyAttr.setCullFace(PolygonAttributes.CULL_NONE);
        polyAttr.setBackFaceNormalFlip(true);
        appear.setPolygonAttributes(polyAttr);
        Shape3D curvedShape = new Shape3D();
        curvedShape.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
        curvedShape.setAppearance(appear);
        CurveAnim curveAnim = new CurveAnim(curvedShape);
        curveAnim.setSchedulingBounds(globalBounds);
        sceneBranch.addChild(curvedShape);
        sceneBranch.addChild(curveAnim);
    }

    private class CurveAnim extends Behavior {

        private static final int NUMPTS = 4;
        private float animpts[] = new float[NUMPTS * 2];
        private float deltas[] = new float[NUMPTS * 2];
        private float width = 100.0f;
        private float height = 100.0f;

        private Shape3D shape3D = null;
        private AWTShapeExtruder extruder = null;
        private AWTShapeExtrusion extrusion = null;
        private WakeupOnElapsedTime time = new WakeupOnElapsedTime(400);

        CurveAnim(Shape3D shape3D) {
            this.shape3D = shape3D;
        }

        public void initialize() {
            extrusion = new AWTShapeExtrusion(100);
            //extrusion.setExtrusionShape(new Ellipse2D.Float(0,0,10,10));
            extruder = new AWTShapeExtruder(0.1, extrusion);
            createShape3D();
            wakeupOn(time);
        }

        public void processStimulus(Enumeration criteria) {
            createShape3D();
            wakeupOn(time);
        }

        private void createShape3D() {

            GeneralPath gp = new GeneralPath();
            /*Shape shhh = new Arc2D.Double(1, 2, 10, 5, 34, 68, Arc2D.PIE);
            Shape shhh2 = new Rectangle2D.Double(0, 5, 10, 20);
            gp.append(shhh, true);
            gp.append(shhh2, true); */
            gp.moveTo(10, 10);
            gp.quadTo(0, 10, 0, 30);
            gp.quadTo(10, 20, 30, 40);
            gp.closePath();
            GeometryArray geom = extruder.getGeometry(generalPath, null);
            GeometryArray geom2 = extruder.getGeometry(gp, null);
            shape3D.setGeometry(geom);
            //shape3D.addGeometry(geom2);
        }

        private void setupBezierCurve() {
            for (int i = 0; i < animpts.length; i += 2) {
                animpts[i + 0] = (float) (Math.random() * width);
                animpts[i + 1] = (float) (Math.random() * height);
                deltas[i + 0] = (float) (Math.random() * 6.0 + 4.0);
                deltas[i + 1] = (float) (Math.random() * 6.0 + 4.0);
                if (animpts[i + 0] > width / 2.0f) {
                    deltas[i + 0] = -deltas[i + 0];
                }
                if (animpts[i + 1] > height / 2.0f) {
                    deltas[i + 1] = -deltas[i + 1];
                }
            }
        }

        private void animate(float[] pts, float[] deltas, int index, float limit) {
            float newpt = pts[index] + deltas[index];
            if (newpt <= 0) {
                newpt = -newpt;
                deltas[index] = (float) (Math.random() * 4.0 + 2.0);
            } else if (newpt >= limit) {
                newpt = 2.0f * limit - newpt;
                deltas[index] = -(float) (Math.random() * 4.0 + 2.0);
            }
            pts[index] = newpt;
        }

        private GeneralPath createBezierPath() {

            /*for (int i = 0; i < animpts.length; i += 2) {
                animate(animpts, deltas, i + 0, width);
                animate(animpts, deltas, i + 1, height);
            }*/

            float[] ctrlpts = animpts;
            int len = ctrlpts.length;
            float prevx = ctrlpts[len - 2];
            float prevy = ctrlpts[len - 1];
            float curx = ctrlpts[0];
            float cury = ctrlpts[1];
            float midx = (curx + prevx) / 2.0f;
            float midy = (cury + prevy) / 2.0f;
            GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO);
            gp.moveTo(midx, midy);
            for (int i = 2; i <= ctrlpts.length; i += 2) {
                float x1 = (midx + curx) / 2.0f;
                float y1 = (midy + cury) / 2.0f;
                prevx = curx;
                prevy = cury;
                if (i < ctrlpts.length) {
                    curx = ctrlpts[i + 0];
                    cury = ctrlpts[i + 1];
                } else {
                    curx = ctrlpts[0];
                    cury = ctrlpts[1];
                }
                midx = (curx + prevx) / 2.0f;
                midy = (cury + prevy) / 2.0f;
                float x2 = (prevx + midx) / 2.0f;
                float y2 = (prevy + midy) / 2.0f;
                gp.curveTo(x1, y1, x2, y2, midx, midy);
                //gp.quadTo(x1, y1, x2, y2);
            }
            gp.closePath();
            return gp;
        }
    }

    private void setLive() {
        sceneBranch.setCapability(BranchGroup.ALLOW_DETACH);
        sceneBranch.compile();
        viewBranch.compile();
        environmentBranch.compile();
        locale.addBranchGraph(sceneBranch);
        locale.addBranchGraph(viewBranch);
        locale.addBranchGraph(environmentBranch);
    }

    private void createUniverse() {
        // Bounds
        globalBounds = new BoundingSphere();
        globalBounds.setRadius(Double.MAX_VALUE);
        //
        // Viewing
        //
        View view = new View();
        view.setPhysicalBody(new PhysicalBody());
        view.setPhysicalEnvironment(new PhysicalEnvironment());
        GraphicsConfigTemplate3D gCT = new GraphicsConfigTemplate3D();
        GraphicsConfiguration gcfg = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getBestConfiguration(gCT);

        try {
            canvas3D = new Canvas3D(gcfg);
        } catch (NullPointerException e) {
            System.out.println("FAIL !!");
            e.printStackTrace();
            System.exit(0);
        } catch (IllegalArgumentException e) {
            System.out.println("FAIL !!");
            e.printStackTrace();
            System.exit(0);
        }

        view.addCanvas3D(canvas3D);
        //
        // SuperStructure
        //
        VirtualUniverse vu = new VirtualUniverse();
        locale = new Locale(vu);
        //
        // BranchGraphs
        //		
        sceneBranch = new BranchGroup();
        viewBranch = new BranchGroup();
        environmentBranch = new BranchGroup();

        // ViewBranch

        TransformGroup viewTG = new TransformGroup();
        viewTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        ViewPlatform vp = new ViewPlatform();
        view.attachViewPlatform(vp);
        DirectionalLight headLight = new DirectionalLight();
        headLight.setInfluencingBounds(globalBounds);
        viewTG.addChild(vp);
        viewTG.addChild(headLight);
        viewBranch.addChild(viewTG);

        // Navigator
        orbitBehInterim = new OrbitBehaviorInterim(canvas3D, viewTG, view, OrbitBehaviorInterim.REVERSE_ALL);
        orbitBehInterim.setSchedulingBounds(globalBounds);
        orbitBehInterim.setClippingEnabled(true);
        Transform3D homeTransform = new Transform3D();
        homeTransform.setTranslation(new Vector3f(50.0f, 50.0f, 220.0f));
        orbitBehInterim.setHomeTransform(homeTransform);
        orbitBehInterim.setHomeRotationCenter(new Point3d(50.0, 50.0, 50.0));
        viewTG.addChild(orbitBehInterim);

        // EnviBranch

        Background bg = new Background();
        bg.setApplicationBounds(globalBounds);
        bg.setColor(0.2f, 0.4f, 1.0f);
        environmentBranch.addChild(bg);
    }
}
